<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <style>
      html,
      body {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
      }

      #webview-patch-iframe {
        width: 100%;
        height: 100%;
        border: none;
      }

      .outer {
        width: 100%;
        height: 100%;
        overflow: hidden;
      }
    </style>

    <script type="module" id="webview-patch">
      const TAG = '[@tomjs:vscode:extension] ';

      function onDomReady(callback, doc) {
        const _doc = doc || document;
        if (_doc.readyState === 'interactive' || _doc.readyState === 'complete') {
          callback();
        } else {
          _doc.addEventListener('DOMContentLoaded', callback);
        }
      }

      let vsCodeApi;

      function getApi() {
        if (vsCodeApi) return vsCodeApi;
        return (vsCodeApi = acquireVsCodeApi());
      }

      function sendInitData(iframe) {
        console.log(TAG + 'init data');
        const dataset = {};
        Object.keys(document.body.dataset).forEach(key => {
          dataset[key] = document.body.dataset[key];
        });

        iframe.contentWindow.postMessage(
          {
            type: '[vscode:extension]:init',
            data: {
              state: getApi().getState(),
              style: document.getElementById('_defaultStyles').innerHTML,
              root: {
                cssText: document.documentElement.style.cssText,
              },
              body: {
                dataset: dataset,
                className: document.body.className,
                role: document.body.getAttribute('role'),
              },
            },
          },
          '*',
        );
      }

      function observeAttributeChanges(element, attributeName, callback) {
        const observer = new MutationObserver(function (mutationsList) {
          for (let mutation of mutationsList) {
            if (mutation.type === 'attributes' && mutation.attributeName === attributeName) {
              callback(mutation.target.getAttribute(attributeName));
            }
          }
        });
        observer.observe(element, { attributes: true });
        return observer;
      }

      // message handler
      let iframeLoaded = false;
      const cacheMessages = [];

      function handleMessage(e) {
        const iframe = document.getElementById('webview-patch-iframe');
        if (!iframeLoaded || !iframe) {
          return;
        }
        if (e.origin.startsWith('vscode-webview://')) {
          iframe.contentWindow.postMessage(e.data, '*');
        } else if ('{{serverUrl}}'.startsWith(e.origin)) {
          const { type, data } = e.data;
          console.log(TAG + ' received:', e.data);
          if (type === '[vscode:client]:postMessage') {
            getApi().postMessage(data);
          }
        }
      }

      window.addEventListener('message', function (event) {
        if (event.origin.startsWith('vscode-webview://')) {
          cacheMessages.push(event);
          return;
        }
        handleMessage(event);
      });

      let isCacheWorking = false;
      setInterval(() => {
        if (isCacheWorking) {
          return;
        }

        isCacheWorking = true;
        if (iframeLoaded) {
          let event = cacheMessages.shift();
          while (event) {
            handleMessage(event);
            event = cacheMessages.shift();
          }
        }
        isCacheWorking = false;
      }, 50);

      onDomReady(function () {
        /**  @type {HTMLIFrameElement} */
        const iframe = document.getElementById('webview-patch-iframe');
        observeAttributeChanges(document.body, 'class', function (className) {
          sendInitData(iframe);
        });

        onDomReady(function () {
          iframeLoaded = true;
          sendInitData(iframe);
        }, iframe.contentDocument);

        iframe.addEventListener('load', function (e) {
          iframeLoaded = true;

          let interval = setInterval(() => {
            try {
              if (document.getElementById('_defaultStyles')) {
                sendInitData(iframe);
                clearInterval(interval);
                return;
              }
            } catch (e) {
              clearInterval(interval);
              console.error(e);
            }
          }, 10);
        });
      });
    </script>
  </head>

  <body>
    <div class="outer">
      <iframe
        id="webview-patch-iframe"
        frameborder="0"
        sandbox="allow-scripts allow-same-origin allow-forms allow-pointer-lock allow-downloads"
        allow="cross-origin-isolated; autoplay; clipboard-read; clipboard-write"
        src="{{serverUrl}}"
      ></iframe>
    </div>
  </body>
</html>
